import { AfterViewInit, OnInit, ViewChild } from '@angular/core';
import { DxDataGridComponent } from 'devextreme-angular/ui/data-grid';
import CustomStore from 'devextreme/data/custom_store';
import DataStore from 'devextreme/data/data_source';
import { Query } from '../http/query';
import { OnReuseDestroy, OnReuseInit } from '../reuse-hooks';
import { DataGridColumnCustomService } from '../service/data-grid-column-custom.service';
import { DataGridPageJumpService } from '../service/data-grid-page-jump.service';
import { detectCallSuperMethod } from '../tools';
import { BaseView } from './base-view';


export class QueryView<U, B, S> extends BaseView<U, B, S> implements AfterViewInit, OnInit, OnReuseInit, OnReuseDestroy {

  @ViewChild('form', { static: false }) formComponent: any;
  @ViewChild('dataGrid', { static: false }) dataGrid: DxDataGridComponent;
  query: Query<U> = new Query();
  disabledInitLoad = true;
  dataSource: DataStore | any;
  /** 当前查询表单校验是否有异常 */
  formMainValidateError: boolean;
  /** 查询参数 */
  queryParams: any = {};
  dataGridColumnCustomService: DataGridColumnCustomService<U, B, S>;
  dataGridPageJumpService: DataGridPageJumpService<U, B, S>;

  private dataGridKey: string | string[];
  private _ngOnInit = false;
  private _ngAfterViewInit = false;
  private _reuseOnDestroy = false;
  private _reuseOnInit = false;
  private _scrollOffset;

  private _isFixed = false;
  private _allowRepaint = true;
  private _timeout;
  constructor() {
    super();
    const injector = (<any>window)._moduleRef.injector;
    this.dataGridColumnCustomService = injector.get(DataGridColumnCustomService);
    this.dataGridPageJumpService = injector.get(DataGridPageJumpService);
    this.dataGridKey = this.getDataGridKey();
    // 初始化dataStore
    this.initDataStore();

    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        if (!this._ngOnInit) {
          this.loggerService.error(new Error('"super.ngOnInit()" Not Implemented ---> ' + this.constructor.name));
        }
        if (!this._ngAfterViewInit) {
          this.loggerService.error(new Error('"super.ngAfterViewInit()" Not Implemented ---> ' + this.constructor.name));
        }
      }, 3000);
    });

    if (!detectCallSuperMethod(this, 'reuseOnInit')) {
      this.loggerService.error(new Error('"super.reuseOnInit()" Not Implemented ---> ' + this.constructor.name));
    }
    if (!detectCallSuperMethod(this, 'reuseOnDestroy')) {
      this.loggerService.error(new Error('"super.reuseOnDestroy()" Not Implemented ---> ' + this.constructor.name));
    }
  }

  ngOnInit(): void {
    this._ngOnInit = true;
    if (!this.queryParams) {
      this.loggerService.error(new Error('queryParams is empty ---> ' + this.constructor.name));
    }

    // 是否提交过数据
    this.queryParams._submitted = false;
    // 数据是否在发送中
    this.queryParams._submitting = false;
  }

  ngAfterViewInit(): void {
    this._ngAfterViewInit = true;
    if (!this.dataGrid) {
      this.loggerService.error(new Error('no dataGrid ---> ' + this.constructor.name));
    }
    this.dataGrid.dataSource = this.dataSource;
    this.dataGridColumnCustomService.columnCustom(this.dataGrid);
    this.dataGridPageJumpService.init(this.dataGrid);

  }

  /** 该方法最终会触发dataGrid组件的Load回掉 */
  onQuery(focusToFirstPage = true) {
    if (!this.queryParams._submitted) {
      this.queryParams._submitted = true;

      // 跨过一次脏值检查来保证表单的isValid实时性
      setTimeout(() => {
        this.onQuery();
      }, 300);
      return;
    }

    if (this.formComponent && !this.formComponent.isValid) {
      this.formMainValidateError = true;
      this.postInvalid();
      return;
    }
    this.formMainValidateError = false;

    if (focusToFirstPage) {
      this.dataSource.pageIndex(0);
    }
    this.dataSource.reload();
  }

  reuseOnDestroy(): void {
    this._reuseOnDestroy = true;
    this._reuseOnInit = false;
    const scrollable = this.dataGrid.instance.getScrollable();
    // 保存DataGrid滚动条位置
    if (scrollable) {
      this._scrollOffset = scrollable.scrollOffset();
    }
  }

  reuseOnInit(): void {
    this._reuseOnInit = true;
    this._reuseOnDestroy = false;
    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        // 还原DataGrid滚动条之前位置
        const scrollable = this.dataGrid.instance.getScrollable();
        if (this._scrollOffset && scrollable && (this._scrollOffset.left > 0 || this._scrollOffset.top > 0)) {
          this.repaint();
          scrollable.scrollTo(this._scrollOffset);
        }
      }, 300);
    });
  }

  /** 子类需要重写父类的方法 */
  protected postInvalid() {
  }

  /** 子类可以重写父类的实现，返回自己的查询结果 */
  protected preLoad(loadOptions: any): Promise<any> | void {
  }

  /** 子类可以重写父类的实现，处理服务器返回的数据 */
  protected postLoad(res: any): any {
    return res;
  }

  /** 子类可以重写父类的实现，返回自己的查询项内容 */
  protected parseQueryParams(loadOptions?: any): any {
    return this.serializeData(this.queryParams);
  }

  protected getDataGridKey(): string | string[] {
    return undefined;
  }

  private initDataStore() {
    this.dataSource = new DataStore(new CustomStore({
      key: this.dataGridKey,
      load: (loadOptions) => {
        if (!this.dataSource._hasInit) {
          this.dataSource._hasInit = true;
          this.dataGrid.instance.option('loadPanel.enabled', true);

          if (this.disabledInitLoad) {
            return Promise.resolve({
              data: [],
              totalCount: 0
            });
          }
        }

        this.query.parseForDev(loadOptions);
        this.query.params = this.parseQueryParams(loadOptions);
        const promise = this.preLoad(loadOptions);
        if (promise && typeof promise.then === 'function') {
          return promise;
        }

        this.dataGrid.instance.beginCustomLoading('');
        const dom = this.dataGrid.instance.element();

        const spanDom = dom.querySelector('span.dx-datagrid-nodata');

        if (spanDom && !spanDom.classList.contains('search-nodata')) {
          spanDom.classList.add('search-nodata');

          const searchNoDataText = this.dataGrid.instance.option('noDataText') === this.i18nService.getValue('@no-data') ?
            this.i18nService.getValue('@search-no-data') : this.dataGrid.instance.option('noDataText');
          this.dataGrid.instance.option('noDataText', searchNoDataText);
        }
        this.queryParams._submitting = true;
        return this.httpService.query(this.query.url, this.query, this.query.httpOptions).then((res) => {
          return {
            data: res.data.items || [],
            totalCount: res.data.count || 0
          };
        }).catch((res) => {
          return {
            data: [],
            totalCount: 0,
            _error: res
          };
        }).then((res) => {
          this.queryParams._submitting = false;
          this.dataGrid.instance.endCustomLoading();
          const _res = this.postLoad(res);
          return _res || res;
        }).finally(() => {
          this.clearSurplusHeight();
          document.dispatchEvent(new Event('click'));
        });
      }
    }));
  }



  /**
   * 监听表格部分事件（优化表格行对齐）
   * 在初始化时没有固定列的情况下不做重绘
   * 监听列变化并重绘
   *  */
  private listeningDataGrid() {
    this._isFixed = this.dataGrid.columns.some(i => i.fixed && i.fixed === true);
    if (this._isFixed) {
      this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          this.dataGrid.columnsChange.subscribe(e => {
            this.repaint();
          });
          // masterDetail展开行时重回导致DataGrid闪烁
          // this.dataGrid.onContentReady.subscribe(e => {
          //   this.repaint();
          // });
        }, 1500);
      });
    }
  }

  /** 重绘 */
  private repaint() {
    // if (this._allowRepaint) {
    if (this._timeout) {
      clearTimeout(this._timeout);
    }
    this._timeout = setTimeout(() => {
      this._timeout = null;
      // this._allowRepaint = false;
      // console.log('%c%s', 'background-color:#000;color:#fff;', ' repaint ');

      this.dataGrid.instance.repaint();
      this.clearSurplusHeight();
    }, 300);
    // } else {
    //   this._allowRepaint = true;
    // }
  }

  /**
   * 清除表格最后一行高度，防止最后一页数据不满一页时高度被撑开
   */
  private clearSurplusHeight() {
    const _nums = Math.ceil(this.dataSource._totalCount / this.dataGrid.paging.pageSize) - 1;
    const isLastIndex = _nums === (this.dataGrid.paging.pageIndex || 0) ? true : false;

    if (isLastIndex) {
      this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          document.querySelectorAll('.dx-freespace-row').forEach((el: HTMLElement) => {
            el.style.height = '0';
          });
          document.querySelector('bz-view-main').scrollTop = 0;
          // console.log('%c%s', 'background-color: #ff0000;color:#fff;', isLastIndex);
        }, 300);
      });
    }
  }
}
